﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Networks;

namespace DiscoveryLogic.Analytics.BusinessLogic.Measures
{
    public class BetweennessCentralityMeasure : INetworkMeasure
    {
        #region Implementation of INetworkMeasure
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Dictionary<Guid, double> GetVerticeMeasure(Graph g)
        {
            Dictionary<Guid,double> centralityMeasures=new Dictionary<Guid, double>();
            List<Vertice> vertices = new List<Vertice>();
            vertices.AddRange(g.Vertices.Values);
            List<Edge> edges = new List<Edge>();
            edges.AddRange(g.Edges.Values);
            NetworkWalker networkWalker = new NetworkWalker(vertices, edges);
            Dictionary<Guid,int> geodesicPathsThroughV = new Dictionary<Guid, int>();
            int allGeodesicPaths = 0;
            foreach(Vertice fromV in g.Vertices.Values)
            {
                Dictionary<Vertice, Route> pathsFromV = networkWalker.GetShortestPathsFrom(fromV);
                foreach(Vertice toV in pathsFromV.Keys)
                {
                    if(toV.ID==fromV.ID)
                        continue;

                    List<Guid> throughVIDs=new List<Guid>();
                    List<Edge> connections = pathsFromV[toV].Edges;
                    foreach (Edge edge in connections)
                    {
                        if (!throughVIDs.Contains(edge.VerticeID1) && edge.VerticeID1 != fromV.ID &&
                            edge.VerticeID1 != toV.ID)
                            throughVIDs.Add(edge.VerticeID1);
                        if (!throughVIDs.Contains(edge.VerticeID2) && edge.VerticeID2 != fromV.ID &&
                            edge.VerticeID2 != toV.ID)
                            throughVIDs.Add(edge.VerticeID2);
                    }
                    if(throughVIDs.Count>0)
                    {
                        foreach(Guid throughVID in throughVIDs)
                        {
                            if (geodesicPathsThroughV.ContainsKey(throughVID))
                                geodesicPathsThroughV[throughVID] = geodesicPathsThroughV[throughVID] + 1;
                            else 
                                geodesicPathsThroughV.Add(throughVID, 1);
                        }
                        allGeodesicPaths += throughVIDs.Count;
                    }
                }
            }
            foreach(Vertice v in vertices)
            {
                double centrality = 0;
                if (geodesicPathsThroughV.ContainsKey(v.ID))
                    centrality = ((double) geodesicPathsThroughV[v.ID])/allGeodesicPaths;
                centralityMeasures.Add(v.ID, centrality);
            }
            
            return centralityMeasures;
        }

        #endregion

        #region Implementation of IMeasure

        public MeasureType MeasureType
        {
            get
            {
                return Measures.MeasureType.Vertice;
            }
        }

        public string MeasureName
        {
            get
            {
                return "Centrality";
            }
        }

        public string Algorithm
        {
            get
            {
                return "Freeman";
            }
        }

        public string Description
        {
            get
            {
                return "";
            }
        }

        #endregion
    }
}
